﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MySql.Data.MySqlClient;

namespace CapaDatos
{
    class CCapaDatos
    {
        #region atributos

        private string servidor;
        private string baseDatos;
        private string cadenaConexion;
        private string usuario;
        private string password;
        private MySqlConnection conexion;
        private bool modoMixto = false;
        private System.Collections.Hashtable colComandos = new System.Collections.Hashtable();

        #endregion

        #region constructores

        public CCapaDatos()
        {
            servidor = "localhost";
            baseDatos = "pollosSakura";
            usuario = "root";
            password = "4dm1n12tr4d0r";
            cadenaConexion = CadenaConexion;
            modoMixto = false;
        }

        #endregion

        #region propiedades
        /// <summary>
        ///	Nombre del equipo servidor de datos.
        /// </summary>

        public string Servidor
        {
            get
            {
                return servidor;
            }
            set
            {
                servidor = value;
            }
        }
        /// <summary>
        /// Nombre de la base de datos a utilizar.
        /// </summary>
        public string BaseDatos
        {
            get
            {
                return baseDatos;
            }
            set
            {
                baseDatos = value;
            }
        }
        /// <summary>
        /// Cadena de conexión completa a la base.
        /// </summary>

        public string CadenaConexion
        {
            get
            {
                if ((servidor.Length != 0) && (baseDatos.Length != 0))
                {
                    System.Text.StringBuilder strCadena = new System.Text.StringBuilder();
                    if (modoMixto == true)
                    {
                        strCadena.Append("data source=<SERVIDOR>;");
                        strCadena.Append("initial catalog=<BASEDATOS>;password='';");
                        strCadena.Append("persist security info=True;");
                        strCadena.Append("user id=<USUARIO>;pwd=<PASSWORD>;packet size=4096");
                        strCadena.Replace("<USUARIO>", this.usuario);/// 'PARA REEMPLAZAR LOS VALORES DE strCadena
                        strCadena.Replace("<SERVIDOR>", this.servidor);/// 'PARA REEMPLAZAR LOS VALORES DE strCadena
                        strCadena.Replace("<BASEDATOS>", this.baseDatos);/// ' IDEM PARA BASE DE DATOS
                        strCadena.Replace("<PASSWORD>", this.password);/// 'IDEM PARA PASSWORD
                    }
                    else
                    {
                        ///CadenaConexion = "Data Source=PC-10AF49FB76BE\SQLEXPRESS;Initial Catalog=db_sipad;Integrated Security=True"
                        strCadena.Append("data source=<SERVIDOR>;");
                        strCadena.Append("initial catalog=<BASEDATOS>;");
                        strCadena.Append("Integrated Security=True");
                        strCadena.Replace("<SERVIDOR>", this.servidor);/// 'PARA REEMPLAZAR LOS VALORES DE strCadena
                        strCadena.Replace("<BASEDATOS>", this.baseDatos);/// ' IDEM PARA BASE DE DATOS
                    }
                    return strCadena.ToString();
                }
                else
                {
                    System.Exception Ex = new System.Exception("No se puede establecer la cadena de conexión");
                    throw Ex;
                }
            }
            set
            {
                cadenaConexion = value;
            }
        }
        #endregion

        #region privadas
        /// <summary>
        /// Crea u obtiene un objeto para conectarse a la base de dtaos.
        /// </summary>
        protected MySqlConnection CrearConexion(string CadenaConexion)
        {
            return new MySqlConnection(CadenaConexion);
        }
        protected MySqlConnection Conexion
        {
            get
            {
                if (null == conexion)
                {
                    conexion = CrearConexion(CadenaConexion);
                }
                if (conexion.State != System.Data.ConnectionState.Open)
                    conexion.Open();
                return conexion;
            }
        }
        #endregion

        #region lecturas
        /// <summary>
        /// Obtiene un DataSet a partir de un Procedimiento Almacenado.
        /// </summary>
        protected MySqlCommand Comando(string ProcedimientoAlmacenado)
        {
            MySqlCommand Com;
            if (colComandos.Contains(ProcedimientoAlmacenado))
                Com = (MySqlCommand)colComandos[ProcedimientoAlmacenado];
            else
            {
                MySqlConnection Con2 = new MySqlConnection(CadenaConexion);
                Con2.Open();
                Com = new MySqlCommand(ProcedimientoAlmacenado, Con2);
                Com.CommandType = System.Data.CommandType.StoredProcedure;
                MySqlCommandBuilder.DeriveParameters(Com);
                Con2.Close();
                Con2.Dispose();
                colComandos.Add(ProcedimientoAlmacenado, Com);

            }
            Com.Connection = (MySqlConnection)this.Conexion;
            Com.Transaction = (MySqlTransaction)this.mTransaccion;
            return (MySqlCommand)Com;
        }

        protected MySqlCommand Comando(string ProcedimientoAlmacenado, MySqlTransaction tran)
        {
            MySqlCommand Com;
            if (colComandos.Contains(ProcedimientoAlmacenado))
                Com = (MySqlCommand)colComandos[ProcedimientoAlmacenado];
            else
            {
                MySqlConnection Con2 = new MySqlConnection(CadenaConexion);
                Con2.Open();
                Com = new MySqlCommand(ProcedimientoAlmacenado, Con2);
                Com.CommandType = System.Data.CommandType.StoredProcedure;
                MySqlCommandBuilder.DeriveParameters(Com);
                Con2.Close();
                Con2.Dispose();
                colComandos.Add(ProcedimientoAlmacenado, Com);

            }
            Com.Connection = tran.Connection;
            Com.Transaction = tran;
            return (MySqlCommand)Com;
        }

        protected void CargarParametros(MySqlCommand Com, System.Object[] Args)
        {
            int Limite = Com.Parameters.Count;
            for (int i = 1; i < Com.Parameters.Count; i++)
            {
                MySqlParameter P = (MySqlParameter)Com.Parameters[i];
                if (i <= Args.Length)
                    P.Value = Args[i - 1];
                else
                    P.Value = null;
            }
        }

        
        protected MySqlDataAdapter CrearDataAdapter(string ProcedimientoAlmacenado, params System.Object[] Args)
        {
            MySqlDataAdapter Da = new MySqlDataAdapter((MySqlCommand)Comando(ProcedimientoAlmacenado));
            if (Args.Length != 0)
                CargarParametros(Da.SelectCommand, Args);
            return (MySqlDataAdapter)Da;
        }

        //TODO, EN LUGAR DEL DATASET RETORNAR UNA LISTA DE OBJETOS.
        public System.Data.DataSet TraerDataset(string ProcedimientoAlmacenado)
        {
            System.Data.DataSet mDataSet = new System.Data.DataSet();
            this.CrearDataAdapter(ProcedimientoAlmacenado).Fill(mDataSet);
            return mDataSet;
        }

        //TODO: EN LUGAR DEL DATASET RETORNAR UNA LISTA DE OBJETOS
        /// <summary>
        /// Obtiene un DataSet a partir de un Procedimiento Almacenado y sus parámetros.
        /// </summary>
        public System.Data.DataSet TraerDataset(string ProcedimientoAlmacenado, params System.Object[] Args)
        {
            System.Data.DataSet mDataSet = new System.Data.DataSet();
            this.CrearDataAdapter(ProcedimientoAlmacenado, Args).Fill(mDataSet);
            return mDataSet;
        }
        /// <summary>
        /// Obtiene un DataTable a partir de un Procedimiento Almacenado.
        /// </summary>

        //TODO: REVISAR SI ESTO ES UTIL.
        public System.Data.DataTable TraerDataTable(string ProcedimientoAlmacenado)
        {
            return TraerDataset(ProcedimientoAlmacenado).Tables[0].Copy();
        }
        /// <summary>
        /// Obtiene un DataSet a partir de un Procedimiento Almacenado y sus parámetros.
        /// </summary>
        public System.Data.DataTable TraerDataTable(string ProcedimientoAlmacenado, System.Object[] Args)
        {
            return TraerDataset(ProcedimientoAlmacenado, Args).Tables[0].Copy();
        }
        /// <summary>
        /// Obtiene un Valor a partir de un Procedimiento Almacenado.
        /// </summary>
        public System.Object TraerValor(string ProcedimientoAlmacenado)
        {
            MySqlCommand Com = Comando(ProcedimientoAlmacenado);
            Com.ExecuteNonQuery();
            System.Object Resp = null;
            foreach (MySqlParameter Par in Com.Parameters)
                if (Par.Direction == System.Data.ParameterDirection.InputOutput || Par.Direction == System.Data.ParameterDirection.Output)
                    Resp = Par.Value;
            return Resp;
        }
        /// <summary>
        /// Obtiene un Valor a partir de un Procedimiento Almacenado, y sus parámetros.
        /// </summary>
        public System.Object TraerValor(string ProcedimientoAlmacenado, params System.Object[] Args)
        {
            MySqlCommand Com = Comando(ProcedimientoAlmacenado);
            CargarParametros(Com, Args);
            Com.ExecuteNonQuery();
            System.Object Resp = null;
            foreach (MySqlParameter Par in Com.Parameters)
                if (Par.Direction == System.Data.ParameterDirection.InputOutput || Par.Direction == System.Data.ParameterDirection.Output)
                    Resp = Par.Value;
            return Resp;
        }
        #endregion
        #region acciones
        public int Ejecutar(string ProcedimientoAlmacenado)
        {
            return Comando(ProcedimientoAlmacenado).ExecuteNonQuery();
        }
        /// <summary>
        /// Ejecuta un Procedimiento Almacenado en la base, utilizando los parámetros.
        /// </summary>
        public int Ejecutar(string ProcedimientoAlmacenado, System.Object[] Args)
        {
            MySqlCommand Com = Comando(ProcedimientoAlmacenado);
            CargarParametros(Com, Args);
            int Resp = Com.ExecuteNonQuery();
            for (int i = 0; i < Com.Parameters.Count; i++)
            {
                MySqlParameter Par = (MySqlParameter)Com.Parameters[i];
                if (Par.Direction == System.Data.ParameterDirection.InputOutput || Par.Direction == System.Data.ParameterDirection.Output)
                    Args.SetValue(Par.Value, i);
            }
            return Resp;
        }
        public int Ejecutar(string ProcedimientoAlmacenado, System.Object[] Args, MySqlTransaction tran)
        {
            MySqlCommand Com = Comando(ProcedimientoAlmacenado, tran);
            CargarParametros(Com, Args);
            int Resp = Com.ExecuteNonQuery();
            for (int i = 0; i < Com.Parameters.Count; i++)
            {
                MySqlParameter Par = (MySqlParameter)Com.Parameters[i];
                if (Par.Direction == System.Data.ParameterDirection.InputOutput || Par.Direction == System.Data.ParameterDirection.Output)
                    Args.SetValue(Par.Value, i);
            }
            return Resp;
        }

        #endregion

        #region transacciones
        protected MySqlTransaction mTransaccion;
        protected bool EnTransaccion = false;
        /// <summary>
        /// Comienza una Transacción en la base en uso.
        /// </summary>
        public MySqlTransaction IniciarTransaccion()
        {
            MySqlConnection oCon = new MySqlConnection();
            oCon = this.CrearConexion(CadenaConexion);
            oCon.Open();
            mTransaccion = oCon.BeginTransaction();
            EnTransaccion = true;
            return mTransaccion;
        }

        /// <summary>
        /// Confirma la transacción activa.
        /// </summary>
        public void TerminarTransaccion()
        {
            try
            {
                mTransaccion.Commit();
            }
            catch (System.Exception Ex)
            {
                throw Ex;
            }
            finally
            {
                mTransaccion = null;
                EnTransaccion = false;
            }
        }
        /// <summary>
        /// Cancela la transacción activa.
        /// </summary>
        public void AbortarTransaccion()
        {
            try
            {
                mTransaccion.Rollback();
            }
            catch (System.Exception Ex)
            {
                throw Ex;
            }
            finally
            {
                mTransaccion = null;
                EnTransaccion = false;
            }
        }
        #endregion

    }
}
